package bsf.baseservice.distributedcache.storage;

import bsf.base.CallBack;
import bsf.base.TimeSpan;
import bsf.baseservice.distributedcache.loadbalance.LoadBalanceFactory;
import bsf.baseservice.distributedcache.storage.aliyunmemcached.AliyunMemcachedCache;
import bsf.baseservice.distributedcache.storage.aliyunmemcached.AliyunMemcachedCacheConfig;
import bsf.baseservice.distributedcache.storage.redis.RedisCache;
import bsf.baseservice.distributedcache.storage.redis.RedisCacheConfig;
import bsf.baseservice.distributedcache.systemruntime.DistributedCacheConnectException;
import bsf.baseservice.distributedcache.systemruntime.DistributedCacheSerializationException;
import bsf.baseservice.distributedcache.systemruntime.EnumCacheType;
import bsf.baseservice.distributedcache.systemruntime.DistributedCacheException;
import bsf.log.ErrorLog;
import bsf.system.configparser.ConfigStringParser;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;

/*
*    * 缓存代理实现工厂
*/
public class CacheFactory
{
	private static BaseCache getCache(String serverconfig)
	{
	    BaseConfig baseConfig = new	ConfigStringParser<BaseConfig>().Parse(serverconfig,BaseConfig.class);
		//旧写法兼容考虑
		if(StringUtils.startsWithIgnoreCase(serverconfig,"redis;"))
			baseConfig.Type="Redis";
		else if(StringUtils.startsWithIgnoreCase(serverconfig,"ssdb;"))
			baseConfig.Type="SSDB";
		else if(StringUtils.startsWithIgnoreCase(serverconfig,"AliyunMemcached;"))
			baseConfig.Type="AliyunMemcached";

		if (StringUtils.equalsIgnoreCase(baseConfig.Type, EnumCacheType.Redis.toString()))
		{
			RedisCache c = new RedisCache();
			c.Config =  new	ConfigStringParser<RedisCacheConfig>().Parse(serverconfig,RedisCacheConfig.class);
			return c;
		}
		else if (StringUtils.equalsIgnoreCase(baseConfig.Type,EnumCacheType.SSDB.toString()))
		{
			/*
			SSDBCache c = new SSDBCache();
			c.setConfig(new SSDBCacheConfig());
			c.getConfig().Parse(serverconfig);
			return c;*/
			throw new DistributedCacheException(String.format("暂不支持%1$s缓存存储实现", EnumCacheType.SSDB.toString()));
		}
		else if (StringUtils.equalsIgnoreCase(baseConfig.Type,EnumCacheType.AliyunMemcached.toString()))
		{
			AliyunMemcachedCache c = new AliyunMemcachedCache();
			c.Config =  new	ConfigStringParser<AliyunMemcachedCacheConfig>().Parse(serverconfig,AliyunMemcachedCacheConfig.class);
			return c;
		}
		else if (StringUtils.equalsIgnoreCase(baseConfig.Type,EnumCacheType.SqlServer.toString()))
		{
			throw new DistributedCacheException(String.format("暂不支持%1$s缓存存储实现", EnumCacheType.SqlServer.toString()));
		}
		else if (StringUtils.equalsIgnoreCase(baseConfig.Type,EnumCacheType.Memcached.toString()))
		{
			throw new DistributedCacheException(String.format("暂不支持%1$s缓存存储实现", EnumCacheType.Memcached.toString()));
		}
		throw new DistributedCacheException("未识别的服务器配置信息");
	}

	public static <T> T getOrSetValue(ArrayList<String> serverconfigs, String key, TimeSpan expiretime, Class<T> cls, CallBack.Func0 action)
	{
		//if (typeof(T) == typeof(string))
		//    throw new DistributedCacheException("不支持string等类型,仅支持class的实体类型");
		if(expiretime.getSeconds()<new TimeSpan(1*1000).getSeconds())
		{
			throw new DistributedCacheException("过期时间不得少于1秒");
		}

		String serverconfig = LoadBalanceFactory.chooseServer(serverconfigs, key);
		try(BaseCache cache = getCache(serverconfig))
		{
			try
			{
				cache.openConn(key);
				T r = null;
				try
				{
					r = cache.<T>getValue(cls);
					if (r != null) //假如key未过期
					{
						return r;
					}
				}
				catch (DistributedCacheSerializationException exp)
				{
					//假如内存的序列化内容和实际的序列化结果不一致的情况,则重新序列化覆盖之,并检查反序列情况
					T r3 = (T)action.invoke();
					boolean success = cache.setValue(r3, expiretime);
					if (success == true)
					{
						try
						{
							T v2 = cache.<T>getValue(cls);
							return v2;
						}
						catch (Exception e)
						{
						}
					}
					ErrorLog.write("DistributedCache序列化出错", exp,CacheFactory.class);
					throw exp;
				}

				if (r == null)
				{
					//假如key已经过期
					T v4 = (T)action.invoke();
					boolean success4 = cache.setValue(v4, expiretime);
					if (success4 == true)
					{
						return v4;
					}
				}
			}
			catch (DistributedCacheConnectException exp)
			{
				ErrorLog.write("DistributedCache连接出错", exp,CacheFactory.class);
				//假如缓存无法连接或连接失败
				T v4 =(T)action.invoke();
				return v4;
			}
			ErrorLog.write("DistributedCache未知严重错误", new RuntimeException(),CacheFactory.class);
			throw new DistributedCacheException("DistributedCache未知严重错误");
		}
	}

	public static <T> T getValue(ArrayList<String> serverconfigs, String key,Class<T> cls) {
		if (cls == String.class) {
			throw new DistributedCacheException("不支持string等类型,仅支持class的实体类型");
		}

		String serverconfig = LoadBalanceFactory.chooseServer(serverconfigs, key);
		try (BaseCache cache = getCache(serverconfig)) {
			try {
				cache.openConn(key);
				T r = null;
				try {
					r = cache.<T>getValue(cls);
					if (r != null) //假如key未过期
					{
						return r;
					}
				} catch (DistributedCacheSerializationException exp) {
					ErrorLog.write("DistributedCache序列化出错", exp, CacheFactory.class);
					throw exp;
				}
				return r;
			} catch (DistributedCacheConnectException exp) {
				ErrorLog.write("DistributedCache连接出错", exp,CacheFactory.class);
				throw new DistributedCacheException("DistributedCache连接出错");
			}
		}
	}

	public static void delete(ArrayList<String> serverconfigs, String[] keys)
	{
		for (String key : keys)
		{
			String serverconfig = LoadBalanceFactory.chooseServer(serverconfigs, key);
			try(BaseCache cache = getCache(serverconfig))
			{
				cache.openConn(key);
				cache.delete();
			}
		}
	}
}